<?php

use Carbon\Carbon;
use App\Enums\TimeTypeEnum;
use Illuminate\Http\Response;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Http;
use Symfony\Component\Mime\MimeTypes;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Support\Facades\Storage;
use EasyWeChat\OfficialAccount\Application;

if (!function_exists('getSql')) {
    function getSql()
    {
        DB::listen(function ($sql) {
            // dump($sql);
            $singleSql = $sql->sql;
            if ($sql->bindings) {
                foreach ($sql->bindings as $replace) {
                    $value = is_numeric($replace) ? $replace : "'" . $replace . "'";
                    $singleSql = preg_replace('/\?/', $value, $singleSql, 1) . ';';
                }
                echo ($singleSql);
            } else {
                echo ($singleSql) . ';';
            }
        });
    }
}

if (!function_exists('formatBytes')) {
    function formatBytes($bytes, $precision = 2)
    {
        $units = array("b", "kb", "mb", "gb", "tb");

        $bytes = max($bytes, 0);
        $pow = floor(($bytes ? log($bytes) : 0) / log(1024));
        $pow = min($pow, count($units) - 1);

        $bytes /= (1 << (10 * $pow));

        return round($bytes, $precision) . " " . $units[$pow];
    }
}



if (!function_exists('gmt_iso8601')) {
    function gmt_iso8601($time)
    {
        return str_replace('+00:00', '.000Z', gmdate('c', $time));
    }
}

if (!function_exists('micro_time')) {
    function micro_time()
    {
        list($usec, $sec) = explode(" ", microtime());
        $time = ($sec . substr($usec, 2, 3));
        return $time;
    }
}


if (!function_exists('getTypeInfoByMimeType')) {
    function getTypeInfoByMimeType($mt)
    {
        $arr = explode('/', $mt);
        return [
            'type' => $arr[0],
            'suffix' => $arr[1]
        ];
    }
}

if (!function_exists('getAliyunOssSign')) {
    function getAliyunOssSign()
    {
        $id = env('ALIYUN_OSS_ACCESSKEY_ID');          // 请填写您的AccessKeyId。
        $key = env('ALIYUN_OSS_ACCESSKEY_SECRET');     // 请填写您的AccessKeySecret。
        $host = 'https://' . env('ALIYUN_OSS_DOMAIN') . '/';
        $dir = 'upload/admin/' . date('Ymd') . '/';
        $now = time();
        $expire = 18000;  //设置该policy超时时间是10s. 即这个policy过了这个有效时间，将不能访问。
        $end = $now + $expire;
        $expiration = gmt_iso8601($end);
        //最大文件大小.用户可以自己设置
        $condition = array(0 => 'content-length-range', 1 => 0, 2 => 5368709120);
        $conditions[] = $condition;

        // 表示用户上传的数据，必须是以$dir开始，不然上传会失败，这一步不是必须项，只是为了安全起见，防止用户通过policy上传到别人的目录。
        $start = array(0 => 'starts-with', 1 => '$key', 2 => $dir);
        $conditions[] = $start;
        $arr = array('expiration' => $expiration, 'conditions' => $conditions);
        $policy = json_encode($arr);
        $base64_policy = base64_encode($policy);
        $string_to_sign = $base64_policy;
        $signature = base64_encode(hash_hmac('sha1', $string_to_sign, $key, true));

        return [
            'accesskey_id' => $id,
            'base64_policy' => $base64_policy,
            'signature' => $signature,
            'dir' => $dir,
            'host' => $host,
        ];
    }
}

if (!function_exists('curlExpress')) {
    function curlExpress($express_id, $express_code = '')
    {
        if ($express_code != '') {
            $query = "no={$express_id}&type={$express_code}";  //参数写在这里
        } else {
            $query = "no={$express_id}";  //参数写在这里
        }
        $response = Http::withToken(env('ALIYUN_EXPRESS_APPCODE'), 'APPCODE')->get('https://wuliu.market.alicloudapi.com/kdi', $query);
        if ($response->successful()) {
            $data = $response->json();
            if (isset($data['status']) && $data['status'] == 0) {
                return $data['result'];
            }
            return $data['msg'];
        } else {
            if($response->header('X-Ca-Error-Message') == 'Api Market Subscription quota exhausted'){
                return null;
            }
            return $response->headers();
        }
    }
}


if (!function_exists('setTimeType')) {
    //1-今年，2-本季度，3-上季度，4-本月，5-上月，6-本周，7-上周，8-昨天，9-今天，10-自定义时间，11-近三个月，12-近半年
    function setTimeType($timeType, &$start, &$end)
    {
        if ($timeType == TimeTypeEnum::今年) {
            $start = Carbon::now()->startOfYear()->toDateTimeString();
            $end = Carbon::now()->endOfYear()->toDateTimeString();
        }

        if ($timeType == TimeTypeEnum::本季度) {
            // 获取当前季度
            $start = Carbon::now()->startOfQuarter()->toDateTimeString();
            $end = Carbon::now()->endOfQuarter()->toDateTimeString();
        }

        if ($timeType == TimeTypeEnum::上季度) {
            $start = Carbon::now()->subQuarter()->startOfQuarter()->toDateTimeString();
            $end = Carbon::now()->subQuarter()->endOfQuarter()->toDateTimeString();
        }
        if ($timeType == TimeTypeEnum::本月) {
            $start = Carbon::now()->startOfMonth()->toDateTimeString();
            $end = Carbon::now()->endOfMonth()->toDateTimeString();
        }
        if ($timeType == TimeTypeEnum::上月) {
            $start = Carbon::now()->subMonth()->startOfMonth()->toDateTimeString();
            $end = Carbon::now()->subMonth()->endOfMonth()->toDateTimeString();
        }
        if ($timeType == TimeTypeEnum::本周) {
            $start = Carbon::now()->startOfWeek()->toDateTimeString();
            $end = Carbon::now()->endOfWeek()->toDateTimeString();
        }
        if ($timeType == TimeTypeEnum::上周) {
            $start = Carbon::now()->subWeek()->startOfWeek()->toDateTimeString();
            $end = Carbon::now()->subWeek()->endOfWeek()->toDateTimeString();
        }
        if ($timeType == TimeTypeEnum::昨天) {
            $start = Carbon::now()->yesterday()->startOfDay()->toDateTimeString();
            $end = Carbon::now()->yesterday()->endOfDay()->toDateTimeString();
        }
        if ($timeType == TimeTypeEnum::今天) {
            $start = Carbon::now()->startOfDay()->toDateTimeString();
            $end = Carbon::now()->endOfDay()->toDateTimeString();
        }

        if ($timeType == TimeTypeEnum::近一周) {
            $start = Carbon::now()->subWeek()->startOfWeek()->toDateTimeString();
            $end = Carbon::now()->endOfWeek()->toDateTimeString();
        }

        if ($timeType == TimeTypeEnum::近一个月) {
            $start = Carbon::now()->subMonth()->startOfMonth()->toDateTimeString();
            $end = Carbon::now()->endOfMonth()->toDateTimeString();
        }

        if ($timeType == TimeTypeEnum::近三个月) {
            $start = Carbon::now()->subMonths(3)->startOfMonth()->toDateTimeString();
            $end = Carbon::now()->endOfMonth()->toDateTimeString();
        }
        if ($timeType == TimeTypeEnum::近半年) {
            $start = Carbon::now()->subMonths(6)->startOfMonth()->toDateTimeString();
            $end = Carbon::now()->endOfMonth()->toDateTimeString();
        }

        if ($timeType == TimeTypeEnum::近一年) {
            $start = Carbon::now()->subYear()->startOfYear()->toDateTimeString();
            $end = Carbon::now()->endOfYear()->toDateTimeString();
        }

        if ($timeType == TimeTypeEnum::自定义时间) {
            $start = Carbon::parse($start)->toDateTimeString();
            $end = Carbon::parse($end)->toDateTimeString();
        }
    }
}

if (!function_exists('getAround')) {
    function getAround($lat, $lon, $raidus)
    {
        $PI = M_PI;

        $latitude = $lat;
        $longitude = $lon;

        $degree = (24901 * 1609) / 360.0;
        $raidusMile = $raidus;

        $dpmLat = 1 / $degree;
        $radiusLat = $dpmLat * $raidusMile;
        $minLat = $latitude - $radiusLat;
        $maxLat = $latitude + $radiusLat;

        $mpdLng = $degree * cos($latitude * ($PI / 180));
        $dpmLng = 1 / $mpdLng;
        $radiusLng = $dpmLng * $raidusMile;
        $minLng = $longitude - $radiusLng;
        $maxLng = $longitude + $radiusLng;

        return [
            'minLongitude' => $minLng,
            'minLatitude' => $minLat,
            'maxLongitude' => $maxLng,
            'maxLatitude' => $maxLat
        ];
    }
}

if (!function_exists('getDistance')) {
    function getDistance($lat1, $lng1, $lat2, $lng2, $miles = true)
    {
        $pi80 = M_PI / 180;
        $lat1 *= $pi80;
        $lng1 *= $pi80;
        $lat2 *= $pi80;
        $lng2 *= $pi80;
        $r = 6372.797; // mean radius of Earth in km
        $dlat = $lat2 - $lat1;
        $dlng = $lng2 - $lng1;
        $a = sin($dlat / 2) * sin($dlat / 2) + cos($lat1) * cos($lat2) * sin($dlng / 2) * sin($dlng / 2);
        $c = 2 * atan2(sqrt($a), sqrt(1 - $a));
        $km = $r * $c;
        return ($miles ? ($km * 0.621371192) : $km);
    }
}

if (!function_exists('signModel')) {
    function signModel(Model $model, array $signKeyArr = [], string $signKey = 'sign')
    {
        //第一步根据signKeyArr获取数据
        $signArr = $model->getAttributes();

        // 检查模型中是否存在$signKey
        if (!isset($signArr[$signKey])) {
            throw new \Exception('模型中不存在' . $signKey . '字段');
        }

        if (count($signKeyArr) > 0) {
            $signArr = array_intersect_key($signArr, array_flip($signKeyArr));
        }

        unset($signArr[$signKey]);

        //按从大到小各变量排序;
        sort($signArr);

        // 把数组中的数字统一转换为两位小数
        foreach ($signArr as $key => $value) {
            if (is_numeric($value)) {
                $signArr[$key] = round($value, 2);
            }
        }

        //展开数组为字符串并添加用户id
        $pre_sign = implode('|', $signArr);
        // dd($pre_sign);
        $pre_sign .= base64_decode(env('APP_KEY'));

        $sign = md5(($pre_sign));

        return $sign;
    }
}

if (!function_exists('checkSignModel')) {
    function checkSignModel(Model $model, array $signKeyArr = [], string $signKey = 'sign')
    {
        //获取模型签名
        $sign = signModel($model, $signKeyArr, $signKey);
        if ($model->$signKey == $sign) {
            return true;
        }

        return false;
    }
}


if (!function_exists('uRight')) {
    /** php 无符号右移 */
    function uRight($a, $n): int
    {
        $c = 2147483647 >> ($n - 1);
        return $c & ($a >> $n);
    }
}

if (!function_exists('md5Hex')) {
    function md5Hex($string): string
    {
        $LOWER = ['0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z'];
        $bytes = unpack("c*", md5($string, true));
        $charArr = [];
        foreach ($bytes as $value) {
            $value = intval($value);
            $charArr[] = $LOWER[uRight(0xF0 & $value, 4)];
            $charArr[] = $LOWER[0x0F & $value];
        }
        return implode("", $charArr);
    }
}

if (!function_exists('randomNumbers')) {
    function randomNumbers($length)
    {
        //生成指定位数的数字随机数
        return rand(pow(10, ($length - 1)), pow(10, $length) - 1);
    }
}

if (!function_exists('maskNumber')) {
    function maskNumber($number)
    {
        if(is_null($number)){
            return '????';
        }
        $number = strval($number); // 确保数字是字符串形式
        $firstDigit = substr($number, 0, 1); // 获取第一位数字
        $maskedPart = str_repeat('?', strlen($number) - 1); // 剩余部分用?代替
        return $firstDigit . $maskedPart;
    }
}
